package com.csc531.managers;

import java.util.ArrayList;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.SyncAdapterType;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Note;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts.Data;
import android.widget.Toast;

import com.csc531.R;

public class FriendManager {
	public final String CLASSMATE_STRING = "classmate";
	private ContentResolver contentResolver;

	private ContentResolver getContentResolver() {
		return this.contentResolver;
	}

	private void setContentResolver(ContentResolver contentResolver) {
		this.contentResolver = contentResolver;
	}

	public FriendManager(ContentResolver contentResolver) {
		setContentResolver(contentResolver);
	}

	public String getContactsNote(long contactId) { 
		String note = null; 
		String[] projection = new String[] { ContactsContract.CommonDataKinds.Note.NOTE }; 
		String whereClause = ContactsContract.Data.RAW_CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; 
		String[] whereParams = new String[]{Long.toString(contactId), ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE}; 
		Cursor c = getContentResolver().query(
				ContactsContract.Data.CONTENT_URI, 
				projection, 
				whereClause, 
				whereParams, 
				null); 

		while (c.moveToNext()) { 
			if(c.getString(0).compareTo(CLASSMATE_STRING) == 0) {
				note = c.getString(0); 
			}
		} 

		c.close(); 

		return note; 
	} 

	public String getContactsPhoneNumber(long contactId) {
		Cursor phones = getContentResolver().query( 
				ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
				null, 
				ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, 
				null, 
				null); 

		String phoneNumber = null;

		if (phones.moveToFirst()) { 
			phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));   
		} 

		phones.close(); 

		return phoneNumber;
	}

	public String getClassmateDisplayName(long contactId) {
		String contact = null;
		Cursor people = getContentResolver().query(
				Uri.parse(ContactsContract.Contacts.CONTENT_URI + "/" + contactId), 
				null, 
				null, 
				null, 
				null);

		if(people.moveToFirst()){
			String contactNotes = getContactsNote(contactId);
			if( contactNotes != null && contactNotes.compareToIgnoreCase(CLASSMATE_STRING) == 0) 
			{
				int nameFieldColumnIndex = people.getColumnIndex(PhoneLookup.DISPLAY_NAME);
				contact = people.getString(nameFieldColumnIndex);
			}
		}

		people.close();

		return contact;
	}

	public String getDisplayName(long contactId) {
		String contact = null;
		Cursor people = getContentResolver().query(
				Uri.parse(ContactsContract.Contacts.CONTENT_URI +"/"+contactId), 
				null, 
				null, 
				null, 
				null);

		people.moveToFirst();

		if(people.moveToFirst()) {
			int nameFieldColumnIndex = people.getColumnIndex(PhoneLookup.DISPLAY_NAME);
			contact = people.getString(nameFieldColumnIndex);
		}

		people.close();

		return contact;
	}


	public String getEmail(long contactId) {
		String email = null; 
		String[] projection = new String[] { ContactsContract.CommonDataKinds.Email.DATA }; 
		String whereClause = ContactsContract.Data.RAW_CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; 
		String[] whereParams = new String[]{Long.toString(contactId), ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE}; 
		Cursor c = getContentResolver().query(
				ContactsContract.Data.CONTENT_URI, 
				projection, 
				whereClause, 
				whereParams, 
				null); 

		if (c.moveToFirst()) { 
			email = c.getString(0); 
		} 

		c.close(); 

		return email; 
	}

	public boolean contactExistsByName(String name) {
		Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

		while(cursor.moveToNext()) {
			long contactId = Integer.valueOf(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))); 
			String contactName = getDisplayName(contactId);

			if(contactName != null && name.compareTo(contactName) == 0) {
				return true;
			}
		}

		cursor.close();

		return false;
	}

	public long getContactId(String name) {
		long id =0 ;
		Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

		while(cursor.moveToNext())
		{
			long contactId = Integer.valueOf(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))); 
			String contact = getDisplayName(contactId);
			if(contact != null && contact.compareTo(name) == 0) {
				id = contactId;
				break;
			}
		}

		cursor.close();

		return id;
	}

	public boolean deleteContact(long contactId, Context context) {
		boolean result = false;

		String whereClause = ContactsContract.Data.RAW_CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.Data.DATA1 + " = ?"; 
		String[] whereParams = new String[]{Long.toString(contactId), ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE, CLASSMATE_STRING}; 

		try {
			getContentResolver().delete(ContactsContract.Data.CONTENT_URI, whereClause, whereParams );
			result = true;
		} catch (Exception e) {
			result = false;	
		} 

		return result;
	}

	public boolean addNewContact(Context context, String name, String email, String phone) {
		AccountManager am = AccountManager.get(context);
		Account[] accounts = am.getAccounts();

		ArrayList<String> contactAccountTypes = new ArrayList<String>();
		SyncAdapterType[] syncs = ContentResolver.getSyncAdapterTypes();

		for (SyncAdapterType sync : syncs) {
			if (ContactsContract.AUTHORITY.equals(sync.authority) &&
					sync.supportsUploading()) {
				contactAccountTypes.add(sync.accountType);
			}
		}

		ArrayList<Account> contactAccounts = new ArrayList<Account>();
		for (Account acct: accounts) {
			if (contactAccountTypes.contains(acct.type)) {
				contactAccounts.add(acct);
			}
		}

		String accountName = new String();
		String accountType = new String();
		if(contactAccounts.size() > 1 ) {
			accountName = contactAccounts.get(0).name;
			accountType = contactAccountTypes.get(0);
		}else{
			accountName = null;
			accountType = null;
		}

		ArrayList<ContentProviderOperation> contentOperationProvider = new ArrayList<ContentProviderOperation>();
		contentOperationProvider.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
				.withValue(RawContacts.ACCOUNT_TYPE, accountType)
				.withValue(RawContacts.ACCOUNT_NAME, accountName)
				.build());

		contentOperationProvider.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(Data.RAW_CONTACT_ID, 0)
				.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
				.withValue(StructuredName.DISPLAY_NAME, name)
				.build());

		contentOperationProvider.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(Data.RAW_CONTACT_ID, 0)
				.withValue(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE)
				.withValue(Note.NOTE, CLASSMATE_STRING)
				.build());

		contentOperationProvider.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(Data.RAW_CONTACT_ID, 0)
				.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
				.withValue(Email.DATA, email)
				.build());

		contentOperationProvider.add(ContentProviderOperation.newInsert(android.provider.ContactsContract.Data.CONTENT_URI)
				.withValueBackReference(Data.RAW_CONTACT_ID, 0)
				.withValue(Phone.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
				.withValue(Phone.NUMBER, phone)
				.build());

		try {
			getContentResolver().applyBatch(ContactsContract.AUTHORITY, contentOperationProvider);
			Toast.makeText(context, R.string.success_adding_new_friend, Toast.LENGTH_SHORT).show();	
			return true;
		} catch (Exception e) {
			Toast.makeText(context, R.string.failure_adding_new_friend, Toast.LENGTH_SHORT).show();	
			return false;
		} 
	}

	public boolean makeExistentContactFriend(Context context, String name) {
		long id = getContactId(name);
		AccountManager am = AccountManager.get(context);
		Account[] accounts = am.getAccounts();

		ArrayList<String> contactAccountTypes = new ArrayList<String>();
		SyncAdapterType[] syncs = ContentResolver.getSyncAdapterTypes();

		for (SyncAdapterType sync : syncs) {
			if (ContactsContract.AUTHORITY.equals(sync.authority) &&
					sync.supportsUploading()) {
				contactAccountTypes.add(sync.accountType);
			}
		}

		ArrayList<Account> contactAccounts = new ArrayList<Account>();
		for (Account acct: accounts) {
			if (contactAccountTypes.contains(acct.type)) {
				contactAccounts.add(acct);
			}
		}

		String accountName = new String();
		String accountType = new String();
		if(contactAccounts.size() > 1 ) {
			accountName = contactAccounts.get(0).name;
			accountType = contactAccountTypes.get(0);
		}else{
			accountName = null;
			accountType = null;
		}

		String note = getContactsNote(id);
		if(note == null) {
			ContentValues values = new ContentValues();
			values.put(RawContacts.ACCOUNT_TYPE, accountType);
			values.put(RawContacts.ACCOUNT_NAME, accountName);
			getContentResolver().update(RawContacts.CONTENT_URI, values, RawContacts.CONTACT_ID +"="+id, null );

			values.clear();
			values.put(Data.RAW_CONTACT_ID, id);
			values.put(Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
			values.put(Note.NOTE, CLASSMATE_STRING);

			try {
				getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
				Toast.makeText(context, R.string.success_adding_new_friend, Toast.LENGTH_SHORT).show();
				return true;
			} catch (Exception e) {
				Toast.makeText(context, R.string.failure_adding_new_friend, Toast.LENGTH_SHORT).show();	
				return false;
			} 
		}else {
			Toast.makeText(context, R.string.existent_friend, Toast.LENGTH_SHORT).show();
			return false;
		}
	}

	public String getContactsPhoneNumberByName(String name) {
		String phoneId = null;
		Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

		while(cursor.moveToNext()) {
			long contactId = Integer.valueOf(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))); 
			String contact = getClassmateDisplayName(contactId);
			if(contact.compareTo(name) == 0) {
				phoneId = getContactsPhoneNumber(contactId);
				break;
			}
		}
		cursor.close();

		return phoneId;
	}

	public ArrayList<String> getFriendsList() {
		ArrayList<String> contacts = new ArrayList<String>();

		Cursor people = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

		while(people.moveToNext()) {
			long contactId = Integer.valueOf(people.getString(people.getColumnIndex(ContactsContract.Contacts._ID))); 
			String contact = getClassmateDisplayName(contactId);
			if(contact != null) {
				contacts.add(contact);
			}
		}
		people.close();

		return contacts;
	}
}
